#include <iostream>
#include <thread>
#include <string>
#include <vector>
#include <chrono>
#include <ctime>
#include <unordered_map>
#include <functional>
#include <semaphore.h>
#include <atomic>
using namespace std;

#include "json.hpp"
#include "group.hpp"
#include "user.hpp"
#include "public.hpp"
using json = nlohmann::json;

#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

// 记录当前系统登录的用户信息
User g_currentUser;
// 记录当前登录用户的好友列表信息
vector<User> g_currentUserFriendList;
// 记录当前登录用户的群组列表信息
vector<Group> g_currentUserGroupList;
// 控制主菜单页面的bool
bool isMainRun = false;

// 用于读写线程之间的通信
sem_t rwsem;
// 记录登录的状态
atomic_bool g_isLoginSuccess{false};

// 打印当前登录成功用户的信息
void showCurrentUserData();
// 接收线程
void readTaskHandler(int clientfd);
// 获取系统时间 （聊天信息需要添加时间信息）
string getCurrentTime();
// 主聊天页面程序
void mainMenu(int clientfd);
// 打印功能界面
void funMenu();

// 主线程发数据，子线程收数据
int main(int argc, char **argv)
{
    if (argc < 3)
    {
        cerr << "command invalid! example: ./ChatClient [ip] [port]" << endl;
        exit(-1);
    }

    char *ip = argv[1];
    uint16_t port = atoi(argv[2]);

    int clientfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == clientfd)
    {
        cerr << "socket create error" << endl;
        exit(-1);
    }

    // 填写client需要连接的server信息+ip+port
    sockaddr_in server;
    memset(&server, 0, sizeof(sockaddr_in));

    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    server.sin_addr.s_addr = inet_addr(ip);

    if (-1 == connect(clientfd, (sockaddr *)&server, sizeof(sockaddr_in)))
    {
        cerr << "connect server error" << endl;
        close(clientfd);
        exit(-1);
    }

    sem_init(&rwsem, 0, 0);

    thread readTask(readTaskHandler, clientfd);
    readTask.detach();

    for (;;)
    {
        // 功能页面
        funMenu();
        int choice = 0;
        
        cin >> choice;
    
        cin.get(); // 读掉缓冲区回车

        switch (choice)
        {
        case 1:
        {
            int id = 0;
            char pwd[50] = {0};
            cout << "userid:";
            cin >> id;
            cin.get();
            cout << "userpassword:";
            cin.getline(pwd, 50);

            json js;
            js["msgid"] = LOGIN_MSG;
            js["id"] = id;
            js["password"] = pwd;
            
            string request = js.dump();

            g_isLoginSuccess = false;

            int len = send(clientfd, request.c_str(), request.size() + 1, 0);
            
            if (len == -1)
            {
                cerr << " send login msg error" << endl;
            }

            sem_wait(&rwsem);

            if (g_isLoginSuccess)
            {
                // 进入聊天主菜单页面
                isMainRun = true;
                mainMenu(clientfd);
            }
        }
        break;

        case 2: // 注册业务
        {
            char name[50] = {0};
            char pwd[50] = {0};
            cout << "username:";
            cin.getline(name, 50); // 这样就能读空格了，遇到回车结束
            cout << "userpassword:";
            cin.getline(pwd, 50);

            json js;
            js["msgid"] = REG_MSG;
            js["name"] = name;
            js["password"] = pwd;
            string request = js.dump();

            int len = send(clientfd, request.c_str(), request.size() + 1, 0);
            if (len == -1)
            {
                cerr << "send reg msg error:" << request << endl;
            }
            
            sem_wait(&rwsem);
        }
        break;
        case 3: // 退出
            close(clientfd);
            sem_destroy(&rwsem);
            exit(0);
        default:
            cerr << "invalid input!" << endl;
            cin.clear(); // 清除错误状态
            //cin.ignore(numeric_limits<streamsize>::max(), '\n'); // 丢弃无效输入
            while(getchar()!='\n')
            {
                
            }
            break;
        }
    }

    return 0;
}

void showCurrentUserData()
{
    cout << "============login user==============" << endl;
    cout << "    current login user => id: " << g_currentUser.getId() << " name: " << g_currentUser.getName() << endl;
    cout << "------------friend list-------------" << endl;
    if (!g_currentUserFriendList.empty())
    {
        for (User &user : g_currentUserFriendList)
        {
            cout <<"    "<< user.getId() << " : " << user.getName() << " : " << user.getState() << endl;
        }
    }
    cout << "------------group list--------------" << endl;
    if (!g_currentUserGroupList.empty())
    {
        for (Group &group : g_currentUserGroupList)
        {
            cout << group.getId() << " : " << group.getName() << " : " << group.getDesc() << endl;
            for (GroupUser &user : group.getUsers())
            {
                cout << "    "<<user.getId() << " : " << user.getName() << " : " << user.getState() << " : " << user.getRole() << endl;
            }
        }
    }
    cout << "====================================" << endl;
}

void doRegResponse(json &responsejs)
{
    if (0 != responsejs["errno"].get<int>()) // 注册失败
    {
        cerr << "name is already exist, register error!" << endl;
    }
    else // 注册成功
    {
        cout << "name register success, userid is [" << responsejs["id"]
             << "], do not forget it!" << endl;
    }
}

void doLoginResponse(json &responsejs)
{
    if (0 != responsejs["errno"]) // 登录失败
    {
        cerr << responsejs["errmsg"] << endl;
        g_isLoginSuccess = false;
    }
    else // 登录成功
    {
        g_currentUser.setId(responsejs["id"]);
        g_currentUser.setName(responsejs["name"]);

        // 清空上次连接剩下的资源
        g_currentUserFriendList.clear();
        g_currentUserGroupList.clear();

        // 开始记录当前好友列表
        if (responsejs.contains("friends"))
        {
            vector<string> vec = responsejs["friends"];
            for (string &str : vec)
            {
                json js = json::parse(str);
                User user;
                user.setId(js["id"]);
                user.setName(js["name"]);
                user.setState(js["state"]);
                g_currentUserFriendList.push_back(user);
            }
        }

        // 记录当前用户的群组列表信息
        if (responsejs.contains("groups"))
        {
            
            vector<string> groupV = responsejs["groups"];
            for (string &str : groupV)
            {
                json js = json::parse(str);
                Group gr;
                gr.setId(js["id"]);
                gr.setName(js["groupname"]);
                gr.setDesc(js["groupdesc"]);
                vector<string> userV = js["users"];
                for (string &user : userV)
                {
                    json us = json::parse(user);
                    GroupUser users;
                    users.setId(us["id"]);
                    users.setName(us["name"]);
                    users.setState(us["state"]);
                    users.setRole(us["role"]);
                    gr.getUsers().push_back(users);
                }
                g_currentUserGroupList.push_back(gr);
            }
        }

        // 显示登录用户的基本信息
        showCurrentUserData();

        // 显示当前用户的离线消息 个人聊天信息或者群组消息
        if (responsejs.contains("offlinemsg"))
        {
            vector<string> vec = responsejs["offlinemsg"];
            for (string &str : vec)
            {
                json js = json::parse(str);
                int msgtype = js["msgid"];
                if (ONE_CHAT_MSG == msgtype)
                {
                    cout << js["time"] << "[" << js["id"] << "]" << js["name"] << " said: " << js["msg"] << endl;
                }

                if (GROUP_CHAT_MSG == msgtype)
                {
                    cout << "群消息[" << js["groupid"] << "]:" << js["time"] << "[" << js["id"] << "]" << js["name"] << " said: " << js["message"] << endl;
                }
            }
        }

        g_isLoginSuccess = true;
    }
}

// 接收线程
void readTaskHandler(int clientfd)
{
    for (;;)
    {
        char buffer[4096] = {0};
        int len = recv(clientfd, buffer, 4096, 0); // 阻塞了
        if (-1 == len || 0 == len)
        {
            close(clientfd);
            exit(-1);
        }

        //cout<<"recvbuf: "<<buffer<<endl;

        json js = json::parse(buffer);
        // 单聊业务 但如果我读了多个数据到clientfd 的话。
        // 但并没有处理
        int msgtype = js["msgid"];
        if (ONE_CHAT_MSG == msgtype)
        {
            cout << js["time"] << "[" << js["id"] << "]" << js["name"] << " said: " << js["msg"] << endl;
            continue;
        }

        if (GROUP_CHAT_MSG == msgtype)
        {
            cout << "群消息[" << js["groupid"] << "]:" << js["time"] << "[" << js["id"] << "]" << js["name"] << " said: " << js["message"] << endl;
            continue;
        }

        if (LOGIN_MSG_ACK == msgtype)
        {
            doLoginResponse(js); // 处理登录响应的业务逻辑
            sem_post(&rwsem);    // 通知主线程，登录结果处理完成
            continue;
        }

        if (REG_MSG_ACK == msgtype)
        {
            doRegResponse(js);
            sem_post(&rwsem); // 通知主线程，注册结果处理完成
            continue;
        }

        if(CHAT_AI_ACK == msgtype)
        {
            std::cout << "=== AI 回复 ===" << std::endl;
            cout<<js["msg"]<<endl;
        }
    }
}

string getCurrentTime()
{
    auto tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    struct tm *ptm = localtime(&tt);
    char date[60] = {0};
    sprintf(date, "%d-%02d-%02d %02d:%02d:%02d",
            (int)ptm->tm_year + 1900, (int)ptm->tm_mon + 1, (int)ptm->tm_mday,
            (int)ptm->tm_hour, (int)ptm->tm_min, (int)ptm->tm_sec);
    return date;
}

void help(int fd = 0, string str = "");
void chat(int, string);
void addfriend(int, string);
void creategroup(int, string);
void addgroup(int, string);
void groupchat(int, string);
void loginout(int, string str = "");
//与ai对话
void chatAI(int,string str = "");

// 系统支持的客户端命令列表
unordered_map<string, string> commandMap = {
    {"help", "显示所有支持的命令，格式help"},
    {"chat", "一对一聊天，格式chat:friendid:message"},
    {"addfriend", "添加好友，格式addfriend:friendid"},
    {"creategroup", "创建群组，格式creategroup:groupname:groupdesc"},
    {"addgroup", "加入群组,格式addgroup:groupid"},
    {"groupchat", "群聊，格式groupchat:groupid:message"},
    {"loginout", "注销，格式loginout"},
    {"chatAI","AI对话，格式chatAI:message"}
    };

// 注册系统支持的客户端命令处理
unordered_map<string, function<void(int, string)>> commandHandlerMap = {
    {"help", help},
    {"chat", chat},
    {"addfriend", addfriend},
    {"creategroup", creategroup},
    {"addgroup", addgroup},
    {"groupchat", groupchat},
    {"loginout", loginout},
    {"chatAI",chatAI}
    };

// 主聊天页面
void mainMenu(int clientfd)
{
    help();
    char buffer[1024] = {0};
    while (isMainRun)
    {
        cin.getline(buffer, 1024);
        string commandbuf(buffer);
        string command; // 存储命令
        int idx = commandbuf.find(":");
        if (-1 == idx)
        {
            command = commandbuf;
        }
        else
        {
            command = commandbuf.substr(0, idx);
        }

        auto it = commandHandlerMap.find(command);
        if (it == commandHandlerMap.end())
        {
            cerr << "invalid input command!" << endl;
            continue;
        }

        it->second(clientfd, commandbuf.substr(idx + 1, commandbuf.size() - idx));
    }
}

void funMenu()
{
    // 登录，注册，退出
    cout << "====================================" << endl;
    cout << "1. login" << endl;
    cout << "2. register" << endl;
    cout << "3. quit" << endl;
    cout << "====================================" << endl;
    cout << "choice:";
}

void help(int, string)
{
    cout << "show command list >>>" << endl;
    for (auto &p : commandMap)
    {
        cout << p.first << " : " << p.second << endl;
    }
    cout << endl;
}

void chat(int fd, string str)
{
    int idx = str.find(":");
    if (-1 == idx)
    {
        cerr << "chat command invalide!" << endl;
        return;
    }
    int friendid = atoi(str.substr(0, idx).c_str());
    string message = str.substr(idx + 1, str.size() - idx);

    json js;
    js["msgid"] = ONE_CHAT_MSG;
    js["id"] = g_currentUser.getId();
    js["name"] = g_currentUser.getName();
    js["to"] = friendid;
    js["msg"] = message;
    js["time"] = getCurrentTime();
    string buffer = js.dump();

    int len = send(fd, buffer.c_str(), buffer.size() + 1, 0);
    if (-1 == len)
    {
        cerr << " send chat msg error -> " << buffer << endl;
    }
}

void addfriend(int fd, string str)
{
    int friendid = atoi(str.c_str());
    json js;
    js["msgid"] = ADD_FRIEND_MSG;
    js["id"] = g_currentUser.getId();
    js["friendid"] = friendid;
    string buffer = js.dump();

    int len = send(fd, buffer.c_str(), buffer.size() + 1, 0);
    if (-1 == len)
    {
        cerr << "send addfriend msg error -> " << buffer << endl;
    }
}

void creategroup(int fd, string str)
{
    int idx = str.find(":");
    if (-1 == idx)
    {
        cerr << "creategroup command invalid!" << endl;
        return;
    }
    string groupname = str.substr(0, idx);
    string groupdesc = str.substr(idx + 1, str.size() - idx);

    json js;
    js["msgid"] = CREATE_GROUP_MSG;
    js["id"] = g_currentUser.getId();
    js["name"] = groupname;
    js["desc"] = groupdesc;

    string buffer = js.dump();
    int len = send(fd, buffer.c_str(), buffer.size() + 1, 0);
    if (-1 == len)
    {
        cerr << " send creategroup msg error -> " << buffer << endl;
    }
}

// 加入群组
void addgroup(int fd, string str)
{
    int groupid = atoi(str.c_str());
    json js;
    js["msgid"] = ADD_GROUP_MSG;
    js["id"] = g_currentUser.getId();
    js["groupid"] = groupid;
    string buffer = js.dump();

    int len = send(fd, buffer.c_str(), buffer.size() + 1, 0);
    if (-1 == len)
    {
        cerr << " send addgroup msg error -> " << buffer << endl;
    }
}

// 群组聊天 groupchat:groupid:message
void groupchat(int fd, string str)
{
    int idx = str.find(":");
    if (-1 == idx)
    {
        cerr << "groupchat command invalid!" << endl;
        return;
    }
    int groupid = atoi(str.substr(0, idx).c_str());
    string message = str.substr(idx + 1, str.size() - idx);
    json js;
    js["msgid"] = GROUP_CHAT_MSG;
    js["id"] = g_currentUser.getId();
    js["groupid"] = groupid;
    js["name"] = g_currentUser.getName();
    js["time"] = getCurrentTime();
    js["message"] = message;
    string buffer = js.dump();
    int len = send(fd, buffer.c_str(), buffer.size() + 1, 0);
    if (-1 == len)
    {
        cerr << " send groupchat msg error -> " << buffer << endl;
    }
}

// 用户注销
void loginout(int fd, string str)
{
    json js;
    js["msgid"] = LOGINOUT_MSG;
    js["id"] = g_currentUser.getId();
    string buffer = js.dump();

    int len = send(fd, buffer.c_str(), buffer.size() + 1, 0);
    if (-1 == len)
    {
        cerr << "send loginout msg error -> " << buffer << endl;
    }
    else
    {
        isMainRun = false;
    }
}


void chatAI(int fd,string str)
{
    cout<<"请耐心等待AI回复，不要关闭程序..."<<endl;
    json js;
    js["msgid"] = CHAT_AI_MSG;
    js["id"] = g_currentUser.getId();
    js["msg"] = str;

    string buffer = js.dump();

    int len = send(fd, buffer.c_str(), buffer.size() + 1, 0);
    if (-1 == len)
    {
        cerr << " send chat msg error -> " << buffer << endl;
    }

}